package zwatcher

import (
	"context"
	"fmt"
	"time"

	genericoptions "gitee.com/youkelike/ziam/zoptions/options"
	"gitee.com/youkelike/ziam/zwatcher/log"
	"gitee.com/youkelike/ziam/zwatcher/options"
	"gitee.com/youkelike/ziam/zwatcher/watcher"
	_ "gitee.com/youkelike/ziam/zwatcher/watcher/all"
	"gitee.com/youkelike/zlog"
	"github.com/go-redsync/redsync/v4"
	"github.com/go-redsync/redsync/v4/redis/goredis/v9"
	"github.com/robfig/cron/v3"

	goredislib "github.com/redis/go-redis/v9"
)

// 基于 cron 包实现的分布式作业系统
type watchJob struct {
	*cron.Cron
	config *options.WatcherOptions
	rs     *redsync.Redsync
}

func newWatchJob(redisOptions *genericoptions.RedisOptions, watcherOptions *options.WatcherOptions) *watchJob {
	// 基于 redis 的分布式锁，控制任务的并发
	client := goredislib.NewClient(&goredislib.Options{
		Addr:     fmt.Sprintf("%s:%d", redisOptions.Host, redisOptions.Port),
		Username: redisOptions.Username,
		Password: redisOptions.Password,
	})
	rs := redsync.New(goredis.NewPool(client))

	// 对 zap 进行简单封装的自定义 log
	logger := log.NewLogger(zlog.SugaredLogger())
	// 构造 cron 对象
	cronJob := cron.New(cron.WithSeconds(), cron.WithChain(cron.SkipIfStillRunning(logger), cron.Recover(logger)))

	return &watchJob{
		Cron:   cronJob,
		config: watcherOptions,
		rs:     rs,
	}
}

func (w *watchJob) addWatchers() *watchJob {
	for name, watch := range watcher.ListWatchers() {
		ctx := context.WithValue(context.Background(), zlog.KeyWatcherName, name)
		// 每个任务一把锁，用 name 作为 key 区分
		if err := watch.Init(ctx, w.rs.NewMutex(name, redsync.WithExpiry(2*time.Hour)), w.config); err != nil {
			zlog.Panicf("construct watcher %s failed: %s", name, err.Error())
		}

		_, _ = w.AddJob(watch.Spec(), watch)
	}

	return w
}
